import fs from 'fs';
import axios from 'axios';
import path from 'path';
import fsPromises from 'fs-promise';
import router from 'koa-router';
import ContentTypeTool from '../lib/ContentTypeTool';
import awaitWrap from '../lib/awaitWrap';
import configTool from '../com/configTool';
import FSTool from '../lib/FSTool/index';
import readFromDB from '../lib/GISServer/Util/readFromDB';
import readFromNet from '../lib/GISServer/Util/readFromNet';
import crypto from 'crypto';
import saveToDB from '../lib/GISServer/Util/saveToDB';
import initDB from '../lib/GISServer/Util/initDB';
import MapBoxTile from '../lib/GISServer/MapboxTile/MapboxTile';
import CesiumTerrain from '../lib/GISServer/CesiumTerrain/CesiumTerrain';


const ProxyRoutes = new router({prefix: '/proxyServer'});

function getRequestParams(ctx: any) {
	const protocol = ctx.params.protocol === 'http' ? 'http://' : 'https://';
	const ip = ctx.params.ip;
	const port = ctx.params.port;

	// 获取请求的 Url，去除掉协议、域名、端口、Get参数的相对路径
	const relativeUrl = ctx.params.url || '';
	let originalUrl = `${protocol}${ip}:${port}/${relativeUrl}`;

	const originalParam = ctx.request.query;

	if (Object.keys(originalParam).length !== 0) {
		originalUrl += '?' + Object.keys(originalParam).map(key => {
			return `${key}=${originalParam[key]}`;
		}).join('&');
	}

	return {protocol, ip, port, relativeUrl, originalUrl};
}

ProxyRoutes
	// http://127.0.0.1:3000/proxyServer/no-cache/http/182.92.77.229/8080/geoserver/ais/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=ais%3Agis_detector_pos&maxFeatures=50&outputFormat=application%2Fjson&BBOX=121.50185823440552,31.231749057769775,121.50619268417358,31.236083507537842
	.get('/no-cache/:protocol/:ip/:port/:url(.*)', async (ctx: any) => {
		const {originalUrl} = getRequestParams(ctx);
		if (originalUrl) {
			let [err, res] = await awaitWrap(axios.get(originalUrl, {responseType: 'arraybuffer'}));
			if (err) {
				ctx.status = 422;
				ctx.body = err;
			} else {
				for (const resKey in res.headers) {
					ctx.set(resKey, res.headers[resKey]);
				}
				ctx.body = res.data;
			}
		}
	})
	// 例如：
	//      原URL：https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json
	//      调用：http://127.0.0.1:3000/proxyServer/auto-cache/https/geo.datav.aliyun.com/443/areas_v3/bound/100000_full.json
	.get('/auto-cache/:protocol/:ip/:port/:url(.*)', async (ctx: any) => {
		const {ip, port, relativeUrl, originalUrl} = getRequestParams(ctx);

		// 缓存文件保存的绝对路径
		let fileSavePath = path.join(configTool.appBasePath, 'temp/fileOut', `${ctx.params.protocol}/${ip}/${port}/${relativeUrl}`);
		let fileDir = path.dirname(fileSavePath);

		if (originalUrl) {
			// 判断是否有缓存文件
			let [err, res] = await FSTool.readFileAsync(fileSavePath);
			// 缓存文件
			if (res) {
				let contentType = ContentTypeTool.getContentType(fileSavePath);
				ctx.set('content-type', contentType);
				ctx.body = res;
			}

			// 未缓存过的其他网络资源
			if (!res) {
				[err, res] = await awaitWrap(axios.get(originalUrl, {responseType: 'arraybuffer'}));
				if (err) {
					ctx.status = 422;
					ctx.body = err;
				} else {
					for (const resKey in res.headers) {
						ctx.set(resKey, res.headers[resKey]);
					}
					ctx.body = res.data;
					// 存入缓存文件
					if (configTool.preservableONFile()) {
						// 如果 Url 里面有文件名，则保存到文件中
						if (!path.extname(fileSavePath)) {
							fileSavePath += ContentTypeTool.getExt(res.headers['content-type']);
						}
						await fsPromises.ensureDir(fileDir);
						fs.writeFileSync(fileSavePath, res.data);
					}
				}
			}
		}
	})
	.get('/wall-Proxy/:protocol/:ip/:port/:url(.*)', async (ctx: any) => {

		const {ip, port, relativeUrl, originalUrl} = getRequestParams(ctx);

		// 缓存文件保存的绝对路径
		const fileSavePath = path.join(configTool.appBasePath, 'temp/fileOut', `${ctx.params.protocol}/${ip}/${port}/${relativeUrl}`);

		const dbPath = '\\' + relativeUrl.replaceAll('/', '\\');

		if (originalUrl) {
			let err, buffer, dataSource;
			// 从数据库中获取文件
			await initDB(ip);
			[err, buffer, dataSource] = await readFromDB({DBName: ip, relativePath: dbPath});

			// 从网络获取
			[err, buffer, dataSource] = await readFromNet({
				url: originalUrl, headers: {}, err, buffer, dataSource, option: {
					proxy: {
						protocol: 'http',
						host: '127.0.0.1',
						port: 7890
					}
				}
			});


			if (buffer) {
				let contentType = ContentTypeTool.getContentType(fileSavePath);
				ctx.set('content-type', contentType);
				ctx.body = buffer;


				// 存入缓存文件
				const md5Str = crypto.createHash('md5').update(buffer).digest('hex');
				if (md5Str) {
					saveToDB({DBName: ip, relativePath: dbPath, buffer}).then();
				}
			} else {
				ctx.status = 422;
				ctx.set('content-type', 'application/json;charset=utf-8');
				ctx.body = err;
				console.warn('代理 翻墙路径失败');
			}


		}
	})
	.get('/api.mapbox.com/v4/mapbox.satellite/:z/:x/:y.webp', async (ctx: any) => {
		let {z, x, y} = ctx.params;
		let [err, buffer] = await MapBoxTile.getSatelliteFileBuffer(z, x, y);

		if (buffer) {
			ctx.set('content-type', 'image/jpeg');
			ctx.body = buffer;
		} else {
			ctx.status = 422;
			ctx.set('content-type', 'application/json;charset=utf-8');
			ctx.body = err;
			console.log('代理 MapBoxTile 瓦片失败', z, x, y);
		}
	})
	.get('/api.mapbox.com/v4/mapbox.terrain-rgb/:z/:x/:y.png', async (ctx: any) => {
		let {z, x, y} = ctx.params;
		let [err, buffer] = await MapBoxTile.getTerrainRGBFileBuffer(z, x, y);

		if (buffer) {
			ctx.set('content-type', 'image/png');
			ctx.body = buffer;
		} else {
			ctx.status = 422;
			ctx.set('content-type', 'application/json;charset=utf-8');
			ctx.body = err;
			console.log('代理 MapBoxTile 瓦片失败', z, x, y);
		}
	})
	.get('/assets.cesium.com/1/:url(.*)', async (ctx: any) => {

		await CesiumTerrain.init();
		console.log(await CesiumTerrain.ionAuthority());
		const url = ctx.params.url;
		let fileSavePath = path.join(configTool.appBasePath, 'temp/fileOut/assets.cesium.com/1/', url);

		// 判断是否有磁盘缓存文件
		let [err, buffer] = await FSTool.readFileAsync(fileSavePath);

		if (err) {
			// 从数据库或网络请求
			[err, buffer] = await CesiumTerrain.getFileBuffer(url);
		}


		if (buffer) {
			ctx.body = buffer;
		} else {
			ctx.status = 422;
			ctx.body = err;
			console.log(`代理 Cesium 官方地形数据失败，${ctx.url}`);
		}
	});

export default ProxyRoutes;
